package com.member.model;

import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;


public class DES3Utils {
    private static final String IV = "union968";
    
    private static String hexStr =  "0123456789ABCDEF";  
    private final static Base64.Encoder encoder = Base64.getEncoder();
    private final static Base64.Decoder decoder = Base64.getDecoder();

    /**
     * DESCBC加密
     *
     * @param src 数据源
     * @param key 密钥，长度必须是8的倍数
     * @return 返回加密后的数据
     * @throws Exception
     */
    public static String encryptDESCBC(final String src, final String key) throws Exception {

        // --生成key,同时制定是des还是DESede,两者的key长度要求不同
        final DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
        final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        final SecretKey secretKey = keyFactory.generateSecret(desKeySpec);

        // --加密向量
        final IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));

        // --通过Chipher执行加密得到的是一个byte的数组,Cipher.getInstance("DES")就是采用ECB模式,cipher.init(Cipher.ENCRYPT_MODE,
        // secretKey)就可以了.
        final Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
        final byte[] b = cipher.doFinal(src.getBytes("UTF-8"));

        // --通过base64,将加密数组转换成字符串
        byte[] bb = encoder.encode(b);
        return new String(bb);
    }

    /**
     * DESCBC解密
     *
     * @param src 数据源
     * @param key 密钥，长度必须是8的倍数
     * @return 返回解密后的原始数据
     * @throws Exception
     */
    public static String decryptDESCBC(final String src, final String key) throws Exception {
        // --通过base64,将字符串转成byte数组
        final byte[] bytesrc = decoder.decode(src);

        // --解密的key
        final DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
        final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        final SecretKey secretKey = keyFactory.generateSecret(desKeySpec);

        // --向量
        final IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));

        // --Chipher对象解密Cipher.getInstance("DES")就是采用ECB模式,cipher.init(Cipher.DECRYPT_MODE,
        // secretKey)就可以了.
        final Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
        final byte[] retByte = cipher.doFinal(bytesrc);

        return new String(retByte);

    }

    // 3DESECB加密,key必须是长度大于等于 3*8 = 24 位哈
    public static String encryptThreeDESECB(final String src, final String key) throws Exception {
        final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
        final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
        final SecretKey securekey = keyFactory.generateSecret(dks);

        final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, securekey);
        final byte[] b = cipher.doFinal(src.getBytes());

        String toEncodeData = new String(encoder.encode(b), "UTF-8").replaceAll("\r", "").replaceAll("\n", "");
        return new String(encoder.encode(toEncodeData.getBytes()),"UTF-8");

    }

    // 3DESECB解密,key必须是长度大于等于 3*8 = 24 位哈
    public static String decryptThreeDESECB(final String src, final String key) throws Exception {
        // --通过base64,将字符串转成byte数组
        final byte[] bytesrc = decoder.decode(src);
        // --解密的key
        final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
        final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
        final SecretKey securekey = keyFactory.generateSecret(dks);

        // --Chipher对象解密
        final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, securekey);
        final byte[] retByte = cipher.doFinal(bytesrc);

        return new String(retByte);
    }


      

      
      /**
       * 3DES 加密
       *
       * @param key  加密秘钥
       * @param data 加密数据
       * @return 加密数据
       */
      public static String tripleDesEncrypt(String keySrc,String encryptData) throws Exception {
    	  
    	  byte[] key = HexStringToBinary(keySrc);

    	  byte[] data = encryptData.getBytes();
    	  
          SecretKey deskey = new SecretKeySpec(key, "DESede");
          String algorithm = "DESede/ECB/NoPadding";
          Cipher cipher = Cipher.getInstance(algorithm);
          data = paddingZero(data);
          byte[] res = null;
          cipher.init(Cipher.ENCRYPT_MODE, deskey);
          res = cipher.doFinal(data);
          return  new String(encoder.encode(res),"UTF-8");
      }


  /**
       * 数据长度不足8倍数的自动补全为8的倍数
       *
       * @param data 加密数据
       * @return
       */
      public static byte[] paddingZero(byte[] src) {
    	 int len = 8;
  		int paddingLength = 8 - src.length % 8;
  		if (len == paddingLength) {
  			return src;
  		}
  		byte[] newsrc = new byte[src.length + paddingLength];
  		System.arraycopy(src, 0, newsrc, 0, src.length);
  		/*System.out.println("***********填充长度后:");
  		for(int i = 0 ; i < newsrc.length ; i++){
  			System.out.printf("%02X", newsrc[i]);
  		}
  		System.out.println();*/
  		return newsrc;
  	}

      /**
       * 3DES解密返回明文
       *
       * @param key  3DES 秘钥
       * @param data 解密数据
       * @return 解密数据
     * @throws InvalidKeyException 
     * @throws BadPaddingException 
     * @throws IllegalBlockSizeException 
     * @throws NoSuchPaddingException 
     * @throws NoSuchAlgorithmException 
       * @throws GeneralSecurityException
       */
      public static String tripleDesDecrypt(String keySrc, String toEncryptData) throws Exception {
    	  
    	  byte[] key = HexStringToBinary(keySrc);
      	  byte[] data = decoder.decode(toEncryptData.getBytes());//HexStringToBinary(key)

          SecretKey deskey = new SecretKeySpec(key, "DESede");

          byte[] res = null;
          String algorithm = "DESede/ECB/NoPadding";
          Cipher cipher = Cipher.getInstance(algorithm);
          cipher.init(Cipher.DECRYPT_MODE, deskey);
          res = cipher.doFinal(data);
          
          return  new String(res,"UTF-8");
      }
      
      
      /** 
       *  
       * @param hexString 
       * @return 将十六进制转换为字节数组 
       */  
      public static byte[] HexStringToBinary(String hexString){  
          //hexString的长度对2取整，作为bytes的长度  
          int len = hexString.length()/2;  
          byte[] bytes = new byte[len];  
          byte high = 0;//字节高四位  
          byte low = 0;//字节低四位  
    
          for(int i=0;i<len;i++){  
               //右移四位得到高位  
               high = (byte)((hexStr.indexOf(hexString.charAt(2*i)))<<4);  
               low = (byte)hexStr.indexOf(hexString.charAt(2*i+1));  
               bytes[i] = (byte) (high|low);//高地位做或运算  
          }  
          return bytes;  
      } 
     

    public static void main(String[] args) throws Exception {
    	//1234567890ABCDEF1234567890ABCDEF 给的是16字节的密钥，但要凑够24个字节，所以截取前面的8个
    	//字节1234567890ABCDEF追加到密钥的后面
    	String keys = "1A2B3C4D5F6E78901A2B3C4D5F6E78901A2B3C4D5F6E7890";
    	System.out.println(DES3Utils.decryptDESCBC("H8VYJYGYLTb0hwWdBAcmMyd93NLJ1rzT","83314f944af4ab3ea2ec27ceef7ccce6"));


  	  String encryptData = "6230746001489405609".trim();
  	  byte[] key = HexStringToBinary(keys);

  	  byte[] data = encryptData.getBytes();
  	  
        SecretKey deskey = new SecretKeySpec(key, "DESede");
        String algorithm = "DESede/ECB/NoPadding";
        Cipher cipher;
        String encryptedStr = "";
		try {
			cipher = Cipher.getInstance(algorithm);
			 data = paddingZero(data);
	          byte[] res = null;
	          cipher.init(Cipher.ENCRYPT_MODE, deskey);
	          res = cipher.doFinal(data);
	          encryptedStr = new String(encoder.encode(res),"UTF-8");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		System.out.println("加密后的加密串: " + encryptedStr.concat("&0"));//tripleDesDecryptToStr
		//3DES加密-- DESede/ECB/NoPadding



	}
}
